<?php
namespace qhweb\phpsm\sm;

use qhweb\phpsm\ecc\sm3\SM3Digest;

class SM3 {

    public static function hash($msg,$format=1){
        $md = array();
        $sm3 = new SM3Digest();
        $msgArray = unpack("C*",$msg);
        $sm3->BlockUpdate($msgArray, 1, sizeof($msgArray));
        $sm3->DoFinal($md, 0);
        if($format){
            return static::_dec2hex($md);
        } else {
            return $md;
        }
    }

    public static function hmac($msg,$key)
    {
        $blockSize = 64; // SM3 的块大小为 512 bit = 64 字节
        $ipad = str_repeat(chr(0x36), $blockSize);
        $opad = str_repeat(chr(0x5C), $blockSize);

        // Step 1: 对密钥进行填充或截断，使其长度为 blockSize (64字节)
        if (strlen($key) > $blockSize) {
            // 如果密钥过长，先对密钥做 SM3 哈希，再转为 32 字节（64 hex char），再填充到 64 字节
            $key = self::hash($key);
            $key = hex2bin($key);
            $key = str_pad($key, $blockSize, chr(0x00));
        } elseif (strlen($key) < $blockSize) {
            // 如果密钥不足 64 字节，右侧填充 0x00
            $key = str_pad($key, $blockSize, chr(0x00));
        }

        // Step 2: 计算 (key ^ ipad) || msg 的 SM3
        $k_ipad = $key ^ $ipad; // 按字节异或
        $inner = $k_ipad . $msg;

        // Step 3: 计算内部哈希：H((K' ⊕ ipad) || m)
        $innerHash = self::hash($inner);

        // Step 4: 计算 (key ^ opad) || innerHash 的 SM3
        $k_opad = $key ^ $opad;
        $outer = $k_opad . hex2bin($innerHash);

        // Step 5: 计算最终 HMAC：H((K' ⊕ opad) || H(...))
        return self::hash($outer);
    }

    protected static function _dec2hex($md){
        $res = array();
        for($i=0; $i<count($md);$i++){
            $res[$i] = sprintf("%02x",$md[$i]);
        }
        return implode("",$res);
    }
}